package com.niiwoo.civet.trade.service.local.newRefund.callback;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.niiwoo.civet.account.enums.RefundStatusEnum;
import com.niiwoo.civet.account.service.trade.TransOrderDubboService;
import com.niiwoo.civet.trade.constant.TradeMqConstant;
import com.niiwoo.civet.trade.dao.entity.Project;
import com.niiwoo.civet.trade.dao.entity.ProjectBorrowerSummary;
import com.niiwoo.civet.trade.dao.entity.RefundOrder;
import com.niiwoo.civet.trade.dao.entity.RefundOrderDetail;
import com.niiwoo.civet.trade.dao.mapper.ProjectBorrowerSummaryMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectMapperExt;
import com.niiwoo.civet.trade.dao.mapper.RefundOrderMapperExt;
import com.niiwoo.civet.trade.enums.RefundOrderAccountingStatusEnum;
import com.niiwoo.civet.trade.enums.RefundTradeTypeEnum;
import com.niiwoo.civet.trade.service.local.newRefund.notify.dto.RefundNotifyMsgDTO;
import com.niiwoo.civet.trade.service.local.newRefund.notify.enums.RefundNotifyRefundStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 还款回调-出款方逻辑处理
 *
 * @author: yuanguang
 * @version 1.0.0
 */
@Slf4j
@Service
public class CallBackBorrowerRefundService {
	
	@Autowired
	private ProjectMapperExt projectMapperExt;

	@Autowired
	private ProjectBorrowerSummaryMapperExt projectBorrowerSummaryMapper;
	
    @Autowired
    private RefundOrderMapperExt refundOrderMapperExt;
    
    @Autowired
    private CallBackBorrowerLocalService callBackBorrowerLocalService;
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    @Reference(version = "1.0.0")
    private TransOrderDubboService transOrderDubboService;
    
    /**
     * 还款回调-借款方逻辑处理
     * 
     * @param refundOrder
     */
	@Transactional(propagation = Propagation.MANDATORY)
	public void refundCallBackAllSuccess(RefundOrder refundOrder, List<RefundOrderDetail> refundOrderDetailList) {
		log.info("出款方回调入参:refundOrder={}", JSONObject.toJSONString(refundOrder));
		Project project = projectMapperExt.selectByPrimaryKey(refundOrder.getProjectId());
		// 标的摘要信息
		ProjectBorrowerSummary summary = projectBorrowerSummaryMapper.selectByPrimaryKey(refundOrder.getProjectId());
		// 更新还款订单状态，同时更新计帐状态为处理中
		updateRefundOrderStatus(refundOrder.getId());

		if(RefundTradeTypeEnum.ADVANCE.getTradeType().equals(refundOrder.getTradeType())){
			log.info("垫付不需要更新出款方数据,batchNo={}",refundOrder.getBatchNo());
			if(Byte.valueOf("0").equals(summary.getIsAdvanced())){
				ProjectBorrowerSummary summaryUpdater = new ProjectBorrowerSummary();
				summaryUpdater.setProjectId(refundOrder.getProjectId());
				summaryUpdater.setIsAdvanced(Byte.valueOf("1"));
				summaryUpdater.setUpdateTime(new Date());
				projectBorrowerSummaryMapper.updateByPrimaryKeySelective(summaryUpdater);
			}
		} else{
			List<String> detailRequestNoList = new ArrayList<String>();
			refundOrderDetailList.forEach(detail->{
				detailRequestNoList.add(detail.getDetailRequestNo());
			});
			log.info("明细请求号:detailRequest={}", Joiner.on(",").skipNulls().join(detailRequestNoList));
			// 调用本地服务还款计划、还款摘要以及标的信息
			callBackBorrowerLocalService.handleRefund(refundOrder, summary, detailRequestNoList,project);
		}
		
		// 还款消息通知MQ请求
		RefundNotifyMsgDTO refundNotifyMsgDTO = new RefundNotifyMsgDTO();
		refundNotifyMsgDTO.setRefundStatus(RefundNotifyRefundStatusEnum.REPAYMENT_FINISH.getStatus());
		refundNotifyMsgDTO.setProjectId(refundOrder.getProjectId());
		refundNotifyMsgDTO.setRefundOrderId(refundOrder.getId());
		refundNotifyMsgDTO.setCurrentPeriod(summary.getCurrentPeriod());
		refundNotifyMsgDTO.setFromSubStatus(project.getSubStatus());
		
		log.info("出款方回调处理完成后，发起还款消息处理MQ通知，请求内容：{}", JSONObject.toJSONString(refundNotifyMsgDTO));
		rabbitTemplate.convertAndSend(TradeMqConstant.REFUND_NOTIFY_HANDLE_EXCHANGE, TradeMqConstant.REFUND_NOTIFY_HANDLE_ROUTINGKEY, refundNotifyMsgDTO);

        // 后续处理（还款记帐、消息通知）
		TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
			@Override
			public void afterCommit() {
				super.afterCommit();
				// 调用帐户中心还款成功记账
				try {
					transOrderDubboService.repaymentSuccessAccounting(refundOrder.getFreezeRequestNo());
					// 成功后更新记帐状态
					updateRefundOrderAccountingStatus(refundOrder.getId());
				} catch (Exception e) {
					log.error("还款回款-借款人还款调用帐户中心还款成功记帐接口异常，异常原因：{}，BatchNo:{}", e.getMessage(), refundOrder.getBatchNo());
				}
			}
		});
    }
	
	/**
	 * 更新还款计划记帐状态
	 * 
	 * 所有投资人或担保回款后，更新还款订单状态：已完成，记帐状态：处理中
	 * 
	 * @param refundOrderId
	 */
	private void updateRefundOrderStatus(Long refundOrderId) {
		RefundOrder updateStatusRefundOrder = new RefundOrder();
		updateStatusRefundOrder.setId(refundOrderId);
		updateStatusRefundOrder.setStatus(RefundStatusEnum.SUCCESS.getValue());
		updateStatusRefundOrder.setAccountingStatus(RefundOrderAccountingStatusEnum.HANDLING.getValue());
		updateStatusRefundOrder.setSuccessTime(new Date()); // 批量交易结束时间
		updateStatusRefundOrder.setUpdateTime(new Date());
		refundOrderMapperExt.updateByPrimaryKeySelective(updateStatusRefundOrder);
	}	
	
	/**
	 * 更新还款计划记帐状态
	 * 
	 * 调用帐户还款成功记帐成功后，更新还款订单记帐状态：成功，处理状态：已结束、
	 * 
	 * @param refundOrderId
	 */
	private void updateRefundOrderAccountingStatus(Long refundOrderId) {
		RefundOrder updateAccountingRefundOrder = new RefundOrder();
		updateAccountingRefundOrder.setId(refundOrderId);
		updateAccountingRefundOrder.setAccountingStatus(RefundOrderAccountingStatusEnum.SUCCESS.getValue());
		updateAccountingRefundOrder.setProcessStatus((byte) 2); // 帐户处理完成之前标记还款订单结束
		updateAccountingRefundOrder.setOverTime(new Date()); // 全部操作结束时间
		updateAccountingRefundOrder.setUpdateTime(new Date());
		refundOrderMapperExt.updateByPrimaryKeySelective(updateAccountingRefundOrder);
	}
}